package com.peng.aviatorscript;

import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableMap;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.annotation.Import;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDouble;
import com.googlecode.aviator.runtime.type.AviatorObject;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Sample1
 *
 * @author: lupeng10
 * @create: 2023-05-18 10:58
 */
public class Sample1 {

    @Test
    public void t1() throws IOException {
        // Expression expression = AviatorEvaluator.getInstance().compileScript("aviator/hello.av");
        // Expression expression = AviatorEvaluator.getInstance().compileScript("aviator/string_interpolation.av");
        // Expression expression = AviatorEvaluator.getInstance().compileScript("aviator/boolean.av");
        Expression expression = AviatorEvaluator.getInstance().compileScript("aviator/function_varargs.av");
        expression.execute();
    }

    /**
     * 自定义函数 执行100W耗时：69
     */
    @Test
    public void t2() throws IOException {
        AviatorEvaluator.addFunction(new AddFunction());
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        Stopwatch stopwatch = Stopwatch.createStarted();
        Expression expression = instance.compile("add", "add(1, 2)", true);
        for (int i = 0; i < 1000000; i++) {
            expression.execute();
        }
        System.out.println("执行100W耗时：" + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    /**
     * 底层反射的方式调用 执行100W耗时：760
     */
    @Test
    public void t4() throws Exception {
        AviatorEvaluator.addFunction(new AddFunction());
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        instance.addModule(StringModel.class);
        Stopwatch stopwatch = Stopwatch.createStarted();
        Expression expression = instance.compile("add", "let str = require('str'); str.add(1, 2)", true);
        for (int i = 0; i < 1000000; i++) {
            expression.execute();
        }
        System.out.println("执行100W耗时：" + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    static class AddFunction extends AbstractFunction {

        @Override
        public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
            Number left = FunctionUtils.getNumberValue(arg1, env);
            Number right = FunctionUtils.getNumberValue(arg2, env);
            return new AviatorDouble(left.doubleValue() + right.doubleValue());
        }

        @Override
        public String getName() {
            return "add";
        }
    }

    @Test
    public void t3() throws NoSuchMethodException, IllegalAccessException {
        AviatorEvaluator.getInstance().addModule(StringModel.class);
        String script = """
                let str = require("str");
                p(str.format(sysdate(), "yyyy-MM-dd"));
                ## 注释
                return str.isBlank(s);
                """;
        System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "hello")));
        // System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "")));
    }

    @Test
    public void t7() throws NoSuchMethodException, IllegalAccessException {

        AviatorEvaluator.getInstance().addModule(StringModel.class);
        String script = "use org.apache.commons.lang3.StringUtils; return StringUtils.isBlank(s) && StringUtils.equals(map.name, 'zhangsan') && map.age == 11;";
        Map<String, Object> newEnv = AviatorEvaluator.newEnv("s", null);
        // newEnv.put("map", ImmutableMap.of("name", "zhangsan", "age", 11));
        newEnv.put("map", ImmutableMap.of("name", "zhangsan"));
        System.out.println(AviatorEvaluator.execute(script, newEnv));
        // System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "")));
    }
    @Test
    public void t8() throws NoSuchMethodException, IllegalAccessException {
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        String script = "use org.apache.commons.lang3.StringUtils; return StringUtils.isBlank(s) && StringUtils.equals(map.name, 'zhangsan') && map.age == 11 && str(a) == '111';";
        Expression expression = instance.compile(script, true);
        Map<String, Object> newEnv = AviatorEvaluator.newEnv("s", null);
        newEnv.put("map", ImmutableMap.of("name", "zhangsan", "age", 11));
        // newEnv.put("a", null);
        newEnv.put("a", 111);
        // newEnv.put("map", ImmutableMap.of("name", "zhangsan"));
        Object result = expression.execute(newEnv);
        System.out.println((boolean) result);
        if (result instanceof Boolean) {
            System.out.println("类型为 Boolean");
        }
    }

    @Test
    public void t9() throws NoSuchMethodException, IllegalAccessException {
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        String script = "return infoId == nil && ep != nil && ep.name == 'zhangsan';";
        Expression expression = instance.compile(script, true);
        // Map<String, Object> newEnv = AviatorEvaluator.newEnv("infoId", 1L);
        Map<String, Object> newEnv = AviatorEvaluator.newEnv("infoId", null);
        newEnv.put("ep", ImmutableMap.of("name", "zhangsan"));
        Object result = expression.execute(newEnv);
        System.out.println((boolean) result);
        if (result instanceof Boolean) {
            System.out.println("类型为 Boolean");
        }
    }

    @Test
    public void t5() throws Exception {
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        instance.addModule(StringModel.class);
        Expression expression = instance.compile("""
                let str = require('str');
                return str.sub(10, 1);
                """);
        System.out.println(expression.execute());
    }

    @Test
    public void t6() throws Exception {
        AviatorEvaluatorInstance instance = AviatorEvaluator.getInstance();
        Expression expression = instance.compile("""
                 return 1 == 1 && false;
                """);
        System.out.println(expression.execute());
    }


    @Import(ns = "str")
    public static class StringModel {
        public static boolean isBlank(String str) {
            return StringUtils.isBlank(str);
        }

        static String format(Date d, String pattern) {
            return new SimpleDateFormat(pattern).format(d);
        }

        static int add(int a, int b) {
            return a + b;
        }

        public static int sub(int a, int b) {
            return a - b;
        }
    }

}
